﻿using IniReadWrite;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using VisionRoc.Tool;

namespace VisionRoc.Core
{
    public class TCPServer
    {
        public delegate void ReceiveMessage1(Socket status);
        ReceiveMessage1 Receive;


        public string ServerPath;
        public TCPServer(string _Path, ReceiveMessage1 _receive)
        {
            //判断文件路径是否存在
            if (!Directory.Exists(_Path))
            {
                Directory.CreateDirectory(_Path);
            }
            ServerPath = _Path + "\\TCPServer.ini";
            if (File.Exists(ServerPath))
            {
                ReadTCPServerParameter();
                Receive = _receive;
                StartSocketServer();
            }
            else
            {
                IP = "127.0.0.1";
                Port = 8001;
                Receive = _receive;
                StartSocketServer();
            }
        }

        //生名一个Socket对象
        private Socket socketServer = null;
        Socket socketClient = null;
        //创建字典集合  键是Clientlp,值是SocketClient
        public Dictionary<string, Socket> CurrentClientlist = new Dictionary<string, Socket>();

        /// <summary>
        /// 服务器IP
        /// </summary>
        public string IP;

        /// <summary>
        /// 服务器端口号
        /// </summary>
        public int Port;

        /// <summary>
        /// 服务器启动状态 是否启动
        /// </summary>
        public bool State = false;

        /// <summary>
        /// 客户端在线状态 判断是否有客户端连接
        /// </summary>
        public bool ClientState = false;

        /// <summary>
        /// 客户端信息
        /// </summary>
        public string ClientInfo;

        /// <summary>
        /// 接收客户端信息
        /// </summary>
        public string Message;

        /// <summary>
        /// 可判断是否接收到客户端发来的消息,True是接收到消息。需要手动恢复false。
        /// </summary>
        public bool ReceiveState = false;

        /// <summary>
        /// 启动服务器
        /// </summary>
        public void StartSocketServer()
        {
            if (PingIP(IP))
            {
                // 第一步调用Socket() 函数创建一个用于通信的套接字。
                socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                // 第二步 给已经创建的套接字绑定一个端口号，这一般通过网络套接口地址和调用Bind() 函数来实现。
                IPEndPoint iPEnd = new IPEndPoint(IPAddress.Parse(IP), Port);
                try
                {
                    socketServer.Bind(iPEnd);
                }
                catch
                {
                    //启动服务器失败
                    Global.AddLogInfoEvent(LogLevel.Error, $"服务器启动失败！IP:{IP.ToString()},端口号:{Port.ToString()}");
                    State = false;
                    return;
                }
                //第三步 ：调用listen()函数使套接字成为一个监听套接字
                socketServer.Listen(10);
                Task.Run(new Action(() =>
                {
                    CheckListening();
                }));

                Global.AddLogInfoEvent(LogLevel.OK, $"服务器启动成功。IP：{IP.ToString()},端口号：{Port.ToString()}");
                State = true;
            }
            else
            {
                Global.AddLogInfoEvent(LogLevel.Error, $"当前IP：{IP},未Ping通创建服务器失败!");
                State = false;
            }

        }

        /// <summary>
        /// 监听客户端线程方法体
        /// </summary>
        private void CheckListening()
        {

            while (socketServer != null)
            {
                //Global.AddLogInfo(LogLevel.OK, $"服务器监听中- - -");
                //第四部：调用accept()函数来接收客户端的连接，这就是可以和客户端通讯了
                try
                {
                    socketClient = socketServer.Accept();
                    State = true;
                }
                catch
                {
                    Global.AddLogInfoEvent(LogLevel.OK, $"服务器关闭");
                    State = false;
                    break;
                }

                Global.AddLogInfoEvent(LogLevel.OK, $"客户端：{socketClient.RemoteEndPoint.ToString()}。上线");
                CurrentClientlist.Add(socketClient.RemoteEndPoint.ToString(), socketClient);
                ClientState = true;
                //UpdateOnliine(client, true);
                Task.Run(new Action(() =>
                {
                    //ReceiveMessage(socketClient);
                    Receive.Invoke(socketClient);
                }));
            }
        }

        /// <summary>
        /// 接收客户端数据的方法体
        /// </summary>
        /// <param name="socketClient"></param>
        private void ReceiveMessage(Socket socketClient)
        {

            while (true)
            {
                //创建一个缓冲区
                byte[] buffer = new byte[1024 * 1024];
                int Length = -1;
                //客户端信息  IP 端口号
                string client = ClientInfo = socketClient.RemoteEndPoint.ToString();
                try
                {
                    Length = socketClient.Receive(buffer);
                }
                catch
                {
                    ReceiveState = false;
                    Global.AddLogInfoEvent(LogLevel.Warn, $"客户端：{client}。下线");
                    CurrentClientlist.Remove(client);
                    ClientState = false;
                    break;
                }

                if (Length > 0)
                {
                    ReceiveState = true;
                    //处理
                    Message = string.Empty;
                    Message = Encoding.Default.GetString(buffer, 0, Length);
                    Global.AddLogInfoEvent(LogLevel.OK, $"接收客户端：{client}  消息 ：{Message}");
                }
                else
                {
                    ReceiveState = false;
                    Global.AddLogInfoEvent(LogLevel.Warn, $"客户端：{client}。下线");
                    CurrentClientlist.Remove(client);
                    ClientState = false;
                    break;
                }

            }
        }

        public void Send(string Msg)
        {
            if (State)
            {
                if (ClientState)
                {
                    try
                    {
                        CurrentClientlist[ClientInfo].Send(Encoding.Default.GetBytes(Msg.Trim()));
                        Global.AddLogInfoEvent(LogLevel.OK, $"发送至客户端{ClientInfo} Info：{Msg}");

                    }
                    catch (Exception ex)
                    {
                        Global.AddLogInfoEvent(LogLevel.Error, $"发送异常报错 已写入文本");
                        TxtAPI.WriteLogTxt(Global.m_ImageSavePath.LogPath, ex.ToString());
                    }

                }
                else
                {
                    Global.AddLogInfoEvent(LogLevel.Info, $"未检测到有客户端在线，消息未发送");
                }

            }
            else
            {
                Global.AddLogInfoEvent(LogLevel.Warn, $"服务器未启动！");
            }

        }

        /// <summary>
        /// 关闭服务器
        /// </summary>
        public void ServerClose()
        {
            if (socketServer != null)
            {
                socketServer.Close();
                socketServer.Dispose();
                socketServer = null;
                State = false;
            }
            else
            {
                MessageBox.Show("服务器未启动");
            }
        }

        ~TCPServer()
        {
            ServerClose();
        }

        public void WriteTCPServerParameter()
        {
            IniAPI.INIWriteValue(ServerPath, "IP", "IP", IP);
            IniAPI.INIWriteValue(ServerPath, "Port", "Port", Port.ToString());
        }

        public void ReadTCPServerParameter()
        {
            IP = IniAPI.INIGetStringValue(ServerPath, "IP", "IP", "0");
            Port = Convert.ToInt32(IniAPI.INIGetStringValue(ServerPath, "Port", "Port", "0"));
        }

        public static bool PingIP(string IP)
        {
            try
            {
                Ping ping = new Ping();
                PingReply pingReply = ping.Send(IP); // m_strIP
                if (pingReply.Status == IPStatus.Success)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch
            {
                return false;
            }
        }

    }
}
